namespace TripleA.Core
{
    using System;
    using Interfaces;
    using Interfaces.Entities;
    using Pipeline;

    /// <summary>
    /// This is used to execute the sequence of steps as defined by the 
    /// pipeline configuration provided. This is typically used in non-BDD
    /// style frameworks. If you want to use TripleA in a BDD style framework
    /// see this link: 
    /// </summary>
    public class Session
    {        
        public static PipelineResult<Context> Execute(IPipelineConfig<Context> config, Context context)
        {
            return Setup(() => config).Execute(context);
        }

        public static IPipeline<Context> Setup(Action<IPipelineConfig<Context>> setup)
        {
            return Setup(() =>
                             {
                                 var config = new PipelineConfig<Context>();
                                 setup(config);
                                 return config;
                             });
        }
        
        public static IPipeline<Context> Setup(Func<IPipelineConfig<Context>> config)
        {
            return new DefaultPipeline<Context>(config());
        }

        public static IPipeline<Context> Setup(Func<IPipeline<Context>> pipelineFactory, Action<IPipelineConfig<Context>> setup)
        {
            var config = new PipelineConfig<Context>();
            setup(config);
            var pipeline = pipelineFactory();
            pipeline.Steps = config.Steps;
            return pipeline;
        }

        public static IPipeline<Context> Setup(Func<IPipeline<Context>> pipelineFactory, Func<IPipelineConfig<Context>> config)
        {
            var pipeline = pipelineFactory();
            pipeline.Steps = config().Steps;
            return pipeline;
        }


        public static PipelineResult<T> Execute<T>(IPipelineConfig<T> config, T context)
            where T : class
        {
            return Setup(() => config).Execute(context);
        }

        public static IPipeline<T> Setup<T>(Action<IPipelineConfig<T>> setup)
            where T : class
        {
            return Setup(() =>
                             {
                                 var config = new PipelineConfig<T>();
                                 setup(config);
                                 return config;
                             });
        }

        public static IPipeline<T> Setup<T>(Func<IPipelineConfig<T>> getConfig)
            where T : class
        {
            return new DefaultPipeline<T>(getConfig());
        }

        public static IPipeline<T> Setup<T>(Func<IPipeline<T>> pipelineFactory, Action<IPipelineConfig<T>> setup)
            where T : class
        {
            var config = new PipelineConfig<T>();
            setup(config);
            var pipeline = pipelineFactory();
            pipeline.Steps = config.Steps;
            return pipeline;
        }

        public static IPipeline<T> Setup<T>(Func<IPipeline<T>> pipelineFactory, Func<IPipelineConfig<T>> getConfig)
        {
            var pipeline = pipelineFactory();
            pipeline.Steps = getConfig().Steps;
            return pipeline;
        }
    }
}